package com.googlecode.stockhamster.bank;

import java.util.List;

import com.googlecode.stockhamster.Constant;

public class BankServiceImpl implements IBank {
	private static Object lock = new Object();

	private int CODE_S = 32;
	private int CODE_L = 64;

	public String[] getList(String adminVer) {
		if (adminVer.equals(Constant.bankAdminCode)) {
			List<String> ls = Account.getList();
			return ls == null ? new String[0] : (String[]) ls.toArray();
		}
		return null;
	}

	public Boolean setMoney(String adminVer, String username, Long money) {
		if (adminVer.equals(Constant.bankAdminCode)) {
			Account acc = Account.get(username);
			if (acc == null)
				return false;
			acc.setMoney(money);
			acc.save();
			return true;
		}
		return false;
	}

	String updateCheck(Check ck, Long amount) {
		synchronized (lock) {
			if (ck.getMoney() == amount) {
				ck.delete();
				return "";
			}
			Check newck = new Check();
			newck.setMoney(ck.getMoney() - amount);
			newck.setUsername(ck.getUsername());
			String newMoneyCode = BankFunc.genMoneyCode(CODE_L, amount);
			newck.setMoneyCode(newMoneyCode);
			newck.insert();
			ck.delete();

			return newMoneyCode;
		}
	}

	/*
	 * For Arbiter
	 */
	public String open(String username) {

		Account srch = Account.get(username);
		if (srch != null)
			return null;
		String code = BankFunc.genCode(CODE_S);
		Account acc = new Account();
		acc.setUsername(username);
		acc.setBankCode(code);
		acc.setMoney(0L);
		acc.insert();

		return code;
	}

	public Boolean close(String username, String code) {

		Account acc = Account.get(username);
		if (acc == null)
			return null;

		if (acc.getBankCode().equals(code)) {
			acc.delete();
			return true;
		}

		return false;
	}

	public String cash(String username, String code, Long amount) {
		synchronized (lock) {
			Account acc = Account.get(username);
			if (acc == null)
				return null;

			if (acc.getBankCode().equals(code) && amount <= acc.getMoney()) {
				String moneyCode = BankFunc.genMoneyCode(CODE_L, amount);
				Check ck = new Check();
				ck.setUsername(username);
				ck.setMoneyCode(moneyCode);
				ck.setMoney(amount);
				if (!ck.insert())
					return null;
				return moneyCode;
			}

			return null;
		}
	}

	public Long getBalance(String username, String code) {
		synchronized (lock) {
			Account acc = Account.get(username);
			if (acc == null)
				return null;

			if (acc.getBankCode().equals(code)) {
				return acc.getMoney();
			}

			return null;
		}
	}

	/*
	 * For StockMarket
	 */
	public String transfer(String targUsername, String moneyCode, Long amount) {
		synchronized (lock) {
			Check ck = Check.get(moneyCode);
			if (ck == null)
				return null;

			Account src = Account.get(ck.getUsername());
			if (src == null)
				return null;

			if (ck.getMoney() < amount)
				return null;
			if (src.getUsername().equals(targUsername)) {
				return updateCheck(ck, amount);
			}
			Account dest = Account.get(targUsername);
			if (dest == null)
				return null;

			if (src.getMoney() >= amount) {
				src.setMoney(src.getMoney() - amount);
				dest.setMoney(dest.getMoney() + amount);
				src.save();
				dest.save();
				return updateCheck(ck, amount);
			}

			return null;
		}
	}

	public Boolean sendBack(String moneyCode) {
		synchronized (lock) {
			Check ck = Check.get(moneyCode);
			if (ck == null)
				return false;

			ck.delete();

			return true;
		}
	}

	public Long query(String moneyCode) {
		synchronized (lock) {
			Check ck = Check.get(moneyCode);
			if (ck == null)
				return 0L;

			return ck.getMoney();
		}
	}

}
